package com.moss.cloud.common.file.utils;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.net.URL;
import java.util.ArrayList;

/**
 * 图片缩放工具
 *
 * @author 瑾年
 * {@code @date} 2023年7月3日
 */
@Slf4j
public class ImgZoomUtil {

    public static final String READ_STREAM = "STREAM";
    public static final String READ_PATH = "PATH";

    /***
     * 将图片缩放到指定的高度或者宽度
     * @param sourceImagePath 图片源地址
     * @param width 缩放后的宽度
     * @param height 缩放后的高度
     * @param auto 是否自动保持图片的原高宽比例
     * @param format 图图片格式 例如 jpg
     * @param inputStream 文件流
     * @param type 网络文件 or 文件流   挡type为文件流 inputStream可以为空，挡type为文件流sourceImagePath
     * image.SCALE_SMOOTH //平滑优先
     * image.SCALE_FAST//速度优先
     * image.SCALE_AREA_AVERAGING //区域均值
     * image.SCALE_REPLICATE //像素复制型缩放
     * image.SCALE_DEFAULT //默认缩放模式
     */
    @SneakyThrows
    public static InputStream getInputStream(String sourceImagePath,
                                             InputStream inputStream,
                                             String type,
                                             int width, int height,
                                             Boolean auto, String format) {
        BufferedImage bufferedImage = commonZoom(sourceImagePath, inputStream, type, width, height, auto);
        return bufferToStream(bufferedImage, format);
    }

    /***
     * 将图片缩放到指定的高度或者宽度
     * @param sourceImagePath 图片源地址
     * @param width 缩放后的宽度
     * @param height 缩放后的高度
     * @param auto 是否自动保持图片的原高宽比例
     * @param format 图图片格式 例如 jpg
     * @param inputStream 文件流
     * @param type 网络文件 or 文件流   挡type为文件流 inputStream可以为空，挡type为文件流sourceImagePath
     * image.SCALE_SMOOTH //平滑优先
     * image.SCALE_FAST//速度优先
     * image.SCALE_AREA_AVERAGING //区域均值
     * image.SCALE_REPLICATE //像素复制型缩放
     * image.SCALE_DEFAULT //默认缩放模式
     */
    @SneakyThrows
    public static byte[] getBytes(String sourceImagePath,
                                  InputStream inputStream,
                                  String type,
                                  int width, int height,
                                  Boolean auto, String format) {
        BufferedImage bufferedImage = commonZoom(sourceImagePath, inputStream, type, width, height, auto);
        return bufferToBytes(bufferedImage, format);
    }

    /***
     * 将图片缩放到指定的高度或者宽度--网络图片
     * @param sourceImagePath 图片源地址
     * @param width 缩放后的宽度
     * @param height 缩放后的高度
     * @param auto 是否自动保持图片的原高宽比例
     * @param inputStream 文件流
     * @param type 网络文件 or 文件流   挡type为文件流 inputStream可以为空，挡type为文件流sourceImagePath
     * image.SCALE_SMOOTH //平滑优先
     * image.SCALE_FAST//速度优先
     * image.SCALE_AREA_AVERAGING //区域均值
     * image.SCALE_REPLICATE //像素复制型缩放
     * image.SCALE_DEFAULT //默认缩放模式
     */
    @SneakyThrows
    public static BufferedImage commonZoom(String sourceImagePath,
                                           InputStream inputStream,
                                           String type,
                                           int width, int height,
                                           Boolean auto) {
        URL url = new URL(sourceImagePath);
        BufferedImage bufferedImage = READ_STREAM.equals(type) ? streamToBuffer(inputStream) : streamToBuffer(url);
        if (Boolean.TRUE.equals(auto)) {
            ArrayList<Integer> paramsArrayList = getAutoWidthAndHeight(bufferedImage, width, height);
            width = paramsArrayList.get(0);
            height = paramsArrayList.get(1);
            log.info("自动调整比例->width:{},->height:{}", width, height);
        }
        Image image = bufferedImage.getScaledInstance(width, height,
                Image.SCALE_SMOOTH);
        BufferedImage outputImage = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = outputImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g2d.drawImage(image, 0, 0, null);
        g2d.dispose();
        return outputImage;
    }


    /**
     * 将double类型的数据转换为int，四舍五入原则
     *
     * @param sourceDouble 
     * @return int
     */
    private static int parseDoubleToInt(double sourceDouble) {
        int result;
        result = (int) sourceDouble;
        return result;
    }

    /***
     *
     * @param bufferedImage 要缩放的图片对象
     * @param width_scale 要缩放到的宽度
     * @param height_scale 要缩放到的高度
     * @return 一个集合，第一个元素为宽度，第二个元素为高度
     */
    private static ArrayList<Integer> getAutoWidthAndHeight(BufferedImage bufferedImage, int width_scale, int height_scale) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();
        double scale_w = getDot2Decimal(width_scale, width);
        log.info("自动调整宽高比例 -> width:{},->scale_w:{}", width, scale_w);
        double scale_h = getDot2Decimal(height_scale, height);
        log.info("自动调整宽高比例 -> height:{},->scale_h:{}", height, scale_h);
        if (scale_w < scale_h) {
            arrayList.add(parseDoubleToInt(scale_w * width));
            arrayList.add(parseDoubleToInt(scale_w * height));
        } else {
            arrayList.add(parseDoubleToInt(scale_h * width));
            arrayList.add(parseDoubleToInt(scale_h * height));
        }
        return arrayList;
    }

    /***
     * 返回两个数a/b的小数点后三位的表示
     * @param a
     * @param b
     * @return
     */
    public static Double getDot2Decimal(int a, int b) {
        BigDecimal bigDecimal_1 = new BigDecimal(a);
        BigDecimal bigDecimal_2 = new BigDecimal(b);
        BigDecimal bigDecimal_result = bigDecimal_1.divide(bigDecimal_2, new MathContext(4));
        Double doubleValue = new Double(bigDecimal_result.toString());
        log.info("相除后的double为:{}", doubleValue);
        return doubleValue;
    }

    /**
     * 将BufferedImage转换为byte[]
     *
     * @param image
     * @return
     */
    @SneakyThrows
    public static byte[] bufferToBytes(BufferedImage image, String format) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, format, os);
        os.flush();
        byte[] imageInByte = os.toByteArray();
        os.close();
        return imageInByte;
    }

    /**
     * BufferedImage 转 InputStream
     *
     * @param image
     * @param format
     * @return
     */
    @SneakyThrows
    public static InputStream bufferToStream(BufferedImage image, String format) {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        ImageIO.write(image, format, outStream);
        return new ByteArrayInputStream(outStream.toByteArray());
    }

    /**
     * inputStream 转byte数组
     *
     * @param inputStream
     * @return
     */
    @SneakyThrows
    public static byte[] inputStreamToBytes(InputStream inputStream) {
        return IOUtils.toByteArray(inputStream);
    }

    /**
     * inputStream 转 BufferedImage
     *
     * @param inputStream
     * @return
     */
    @SneakyThrows
    public static BufferedImage streamToBuffer(InputStream inputStream) {
        return ImageIO.read(inputStream);
    }

    /**
     * base64 转 InputStream
     *
     * @param base64
     * @return
     */
    public static InputStream base64ToStream(String base64) {
        byte[] bytes = FileDataPreUtil.base64ToBytes(base64);
        return new ByteArrayInputStream(bytes);
    }

    /**
     * inputStream 转 BufferedImage
     *
     * @param input
     * @return
     */
    @SneakyThrows
    public static BufferedImage streamToBuffer(URL input) {
        return ImageIO.read(input);
    }


    public static void main(String[] args) throws IOException {
        String sourceImagePath = "https://qxht.xiaomy.net/file/jinnian/20241123/a4a101f8187e4984b7169c7422cb02cc.jpg";
        String destinationPath = "D:\\我的图片\\456.jpg";
        //scaleImage(sourceImagePath,destinationPath,0.5,"png");
        BufferedImage outputImage = commonZoom(sourceImagePath, null, READ_PATH, 360, 1920, true);
        ImageIO.write(outputImage, "jpg", new File(destinationPath));

    }
}
